﻿using java.io;
using java.lang;
using java.nio.channels;
using SkiaSharp;
using sun.misc;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using yzrilyzr.crypto;
using yzrilyzr.crypto.mode;
using yzrilyzr.FAQ.bot;
using yzrilyzr.FAQ.client;
using yzrilyzr.FAQ.constants;
using yzrilyzr.FAQ.protocol;
using yzrilyzr.FAQ.utils;
using yzrilyzr.util;
using Console = System.Console;
using Exception = System.Exception;
using Process = System.Diagnostics.Process;

namespace FAQ_UI
{
	public class FAQUtil
	{
		public static NinePatchLruCache bubbles = new NinePatchLruCache(20 * 1024 * 1024, 15 * 60000);
		public static DrawableLruCache imageCache = new DrawableLruCache(512 * 1024 * 1024, 15 * 60000);
		public static FAQClient client { get; set; }
		public static FAQEventBus eventBus { get; set; }
		public static DB settings { get; set; }
		private static MediaPlayer faqsound;
		public static bool isSafe = false;

		static FAQUtil()
		{
			faqsound = new MediaPlayer();
			string tmp = Path.GetTempFileName() + ".mp3";
			byte[] by = getResourceByte("/assets/faq/faq.mp3");
			System.IO.File.WriteAllBytes(tmp, by);
			faqsound.Open(new Uri(tmp, UriKind.RelativeOrAbsolute));

			byte[] by2 = getResourceByte("/cppdll/FAQProtect1.dll");
			tmp = System.IO.Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
			Console.WriteLine(tmp);
			System.IO.File.WriteAllBytes(tmp + "\\FAQProtect1.dll", by2);
			new System.Threading.Thread(() =>
			{
				if (CheckVM()) isSafe = false;
				else isSafe = true;
				Console.WriteLine(CheckVM());
			}).Start();
		}
		public static void openDownloadBigData(MsgPack ms, FAQID toid)
		{
			string s = ms.getString(K.LOCALURI);
			if (s == null)
			{
				if (ms.getLength() < MsgPack.dataLimit())
				{
					byte[] data = FAQUtil.client.getBigData(ms);
					if (data == null)
					{
						MessageBox.Show("文件已失效");
						return;
					}
					java.io.File tmpFile = new java.io.File(getDownloadPath() + "/" + ms.getString(K.NAME));
					while (tmpFile.exists()) tmpFile = FileUtil.nextName(tmpFile);
					Util.write(tmpFile.getAbsolutePath(), data);
					ms.put(K.LOCALURI, s = tmpFile.getAbsolutePath());
					if (toid != null) FAQUtil.client.getChatRecordHelper(toid).modify(ms);
				}
				else
				{
					MessageBox.Show("没有本地文件");
					ms.setProgress(0);
					if (toid != null) FAQUtil.client.getChatRecordHelper(toid).modify(ms);
					return;
				}
			}
			java.io.File ff = new java.io.File(s);
			if (!ff.exists())
			{
				MessageBox.Show("本地文件不存在");
				ms.setProgress(0);
				if (toid != null) FAQUtil.client.getChatRecordHelper(toid).modify(ms);
				return;
			}
			Process.Start(s);

		}
		public static string getDownloadPath()
		{
			string p= Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\FAQ\\Download\\";
			if(!Directory.Exists(p))Directory.CreateDirectory(p);
			return p;
		}
		public static string getSuffix(byte[] data)
		{
			if (data == null || data.Length == 0) return "";
			string mime = MIMEUtil.getMIMETypeForUnknown(new ByteArrayInputStream(data));
			string suffix = "png";
			Logger.getDef().d(mime);
			if (mime.Contains("png")) suffix = "png";
			else if (mime.Contains("jpeg")) suffix = "jpg";
			else if (mime.Contains("gif")) suffix = "gif";
			return suffix;
		}
		public static Drawable getAvatar(FAQID uuid)
		{
			if (uuid == null) return null;
			return imageCache.get("Avatar" + uuid, new Loader<Drawable>(() =>
			{
				Drawable s = null;
				if (UUIDs.isReserved(uuid))
				{
					if (UUIDs.CHATROOM.equals(uuid)) s = getDrawableRes("/assets/bug.png");
					else if (UUIDs.FAVOURITE.equals(uuid)) s = getDrawableRes("/assets/rev_favourite.png");
				}
				else s = getDrawable(FAQClient.getHead(uuid));
				return s == null ? getDefAvatar() : new RoundDrawable(s);
			}));
		}

		public static Drawable getBackground(FAQID uuid)
		{
			return imageCache.get("Background" + uuid, new Loader<Drawable>(() =>
			{
				Drawable bitmapImage = getDrawable(FAQClient.getBack(uuid));
				return bitmapImage == null ? getDefBack() : bitmapImage;
			}));
		}

		public static Drawable Text2Icon(string text, int size)
		{
			return new TextDrawable(text, size, getIconFont());
		}

		public static NinePatchDrawable getBubble(FAQID uuid)
		{
			return bubbles.get("Bubble" + uuid, new Loader<NinePatchDrawable>(() =>
			{
				Drawable bitmapImage = getDrawable(FAQClient.getBubble(uuid));
				return bitmapImage == null ? getDefBubble() : new NinePatchDrawable(bitmapImage);
			}));
		}

		public static string getDescription(FAQID toid)
		{
			if (UUIDs.isNull(toid)) return "null faqid";
			return FAQClient.getDescription(toid);
		}

		public static string getCommNameOrName(FAQID toid)
		{
			if (UUIDs.isNull(toid)) return "null faqid";
			string nam = FAQClient.getName(toid);
			string comm = client.getCommentName(toid);
			if (comm != null) return string.Format("{0} ({1})", comm, nam);
			else return ("" == nam ? "[昵称为空]" : nam);
		}

		public static string getTimeStringByNow(long time)
		{
			long oneDay = 24 * 60 * 60 * 1000;
			long now = java.lang.System.currentTimeMillis();
			long d = now - time;
			if (d < oneDay) return string.Format("{0:HH:mm}", new DateTime(time));
			if (oneDay < d && d < oneDay * 2) return "昨天";
			if (d < 7 * oneDay)
			{
				string[] weekdays = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
				return weekdays[Convert.ToInt32(new DateTime(time).DayOfWeek)];
			}
			return string.Format("{0:yyyy-MM-dd}", new DateTime(time));
		}

		public static void initFAQClient(int hash)
		{
			client = new FAQClient(hash);
			client.addReceiver(new DefMsgPackReceiver());
		}

		public static Drawable getDrawable(byte[] b)
		{
			if (b == null || b.Length == 0) return null;
			try
			{
				byte[] mag = new byte[] { b[0], b[1], b[2] };
				string magic = ASCIIEncoding.ASCII.GetString(mag).ToLower();
				if (magic == "gif") return new GifDrawable(b);
				else if (magic.Contains("{")) { return new LottieDrawable(b); }
				else if (magic == "vec") { return null; }
				else return new BitmapDrawable(b);
			}
			catch (Exception)
			{
				return new ImageErrDrawable();
			}
		}
		public static Typeface getIconFont()
		{
			FontFamily fontFamily = App.Current.Resources["icon"] as FontFamily;
			return fontFamily.GetTypefaces().First();
		}
		public static Typeface getFAQIconFont()
		{
			FontFamily fontFamily = App.Current.Resources["faqicon"] as FontFamily;
			return fontFamily.GetTypefaces().First();
		}
		internal static Drawable getDefAvatar()
		{
			return imageCache.get("AvatarDefault", new Loader<Drawable>(() =>
			{
				return getDrawableRes("/assets/faq/user.png");
			}));
		}

		internal static Drawable getDefBack()
		{
			return getDrawableRes("/assets/faq/back.png");
		}

		internal static NinePatchDrawable getDefBubble()
		{
			return new NinePatchDrawable(getDrawableRes("/assets/faq/bubbles/bubble_def.png"));
		}

		internal static Drawable getMsgPic(MsgPack p)
		{
			if (p.getDigest() == null) return null;
			return imageCache.get("chatpic" + Util.b64(p.getDigest()), new Loader<Drawable>(() =>
			{
				byte[] pp = client.getBigData(p);
				return getDrawable(pp);
			}));
		}

		public static byte[] readAllBytes(Stream stream)
		{
			int av = (int)stream.Length;
			byte[] by = new byte[av];
			stream.Read(by, 0, av);
			return by;
		}

		public static byte[] readAllBytes(string file)
		{
			using (Stream s = new FileStream(file, FileMode.Open, FileAccess.Read))
			{
				return readAllBytes(s);
			}
		}

		internal static Drawable getDrawableRes(string path)
		{
			return getDrawable(getResourceByte(path));
		}

		internal static Drawable getDrawableFile(string path)
		{
			try
			{
				using (Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
				{
					return getDrawable(readAllBytes(stream));
				}
			}
			catch (Exception ex)
			{
				return null;
			}
		}

		public static byte[] ToByteArray(BitmapEncoder encoder, ImageSource imageSource)
		{
			byte[] bytes = null;
			var bitmapSource = imageSource as BitmapSource;
			if (bitmapSource == null) return null;
			encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
			using (var stream = new MemoryStream())
			{
				encoder.Save(stream);
				bytes = stream.ToArray();
			}
			return bytes;
		}

		public static string getClientPath()
		{
			return settings.getString(D.SETTINGS, "ClientPath", Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\FAQ\\Client");
		}

		public static string getServerPath()
		{
			return settings.getString(D.SETTINGS, "ServerPath", Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\FAQ\\Server");
		}

		public static void playFAQsound()
		{
			faqsound.Volume = 0.2f;
			faqsound.Stop();
			faqsound.Play();
		}

		public static byte[] getResourceByte(string path)
		{
			Uri uri = new Uri(path, System.UriKind.Relative);
			using (Stream stream = App.GetResourceStream(uri).Stream)
			{
				return readAllBytes(stream);
			}
		}

		public static System.Drawing.Icon ToIcon(Drawable imageSource)
		{
			int width = 128, height = 128;
			var drawingVisual = new DrawingVisual();
			using (DrawingContext dc = drawingVisual.RenderOpen())
			{
				imageSource.setBounds(0, 0, width, height);
				imageSource.draw(dc);
			}
			RenderTargetBitmap bitmap = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Default);
			bitmap.Render(drawingVisual);
			var b = ToByteArray(new PngBitmapEncoder(), bitmap);
			var ss = Convert.ToString((b.Length), 16).PadLeft(6, '0');
			var daoshu1 = ss.Substring(4, 2);
			var daoshu2 = ss.Substring(2, 2);
			var daoshu3 = ss.Substring(0, 2);
			byte[] icoStart = {  0x00,  0x00,  0x01,  0x00, 0x01,  0x00,0 ,0 , 0x00,  0x00,0x01,  0x00,0x20,  0x00,
				Convert.ToByte(Convert.ToInt16(daoshu1 ,16)),Convert.ToByte(Convert.ToInt16(daoshu2,16))
				,Convert.ToByte(Convert.ToInt16(daoshu3,16)),  0x00,0x16,  0x00,0x00,  0x00 };
			byte[] icoData = icoStart.Concat(b).ToArray();
			string IcoPath1 = Path.GetTempFileName() + ".ico";
			System.IO.File.WriteAllBytes(IcoPath1, icoData);
			return System.Drawing.Icon.ExtractAssociatedIcon(IcoPath1);
		}

		[DllImport("FAQProtect1.dll", CallingConvention = CallingConvention.Cdecl)]
		public static extern bool CheckVM();

		[DllImport("FAQProtect1.dll", CallingConvention = CallingConvention.Cdecl)]
		public static extern int isScreenProcessRunning();

		[DllImport("FAQProtect1.dll", CallingConvention = CallingConvention.Cdecl)]
		public static extern int isScreenServiceRunning();

		internal static BitmapImage loadBitmap(byte[] b)
		{
			if (b == null) return null;
			BitmapImage bitmap = new BitmapImage();
			using (MemoryStream ms = new MemoryStream(b))
			{
				bitmap.BeginInit();
				bitmap.CacheOption = BitmapCacheOption.OnLoad;
				bitmap.StreamSource = ms;
				bitmap.EndInit();
			}
			return bitmap;
		}

		private class DefMsgPackReceiver : MsgPackReceiver
		{
			private Logger logger = new Logger("DefMsgPackReceiver");

			public async void receive(MsgPackTransfer mpt, MsgPack mp)
			{
				//logger.d(mp);
				int cmd = mp.getCmd();
				if (cmd == C.SESSION_STOPPED)
				{
					if (client.isLogin()) return;
					await Task.Delay(1000);
					if (FAQUtil.settings.contK(D.SETTINGS, "ServerAddress"))
					{
						logger.i("AutoConnect", FAQUtil.settings.getString(D.SETTINGS, "ServerAddress"));
						FAQUtil.client.connectTo(FAQUtil.settings.getString(D.SETTINGS, "ServerAddress"));
					}
				}
				else if (cmd == C.NEEDDIGEST)
				{
					byte[] pp = client.getBigData(mp);
					if (pp != null)
					{
						App.Current.Dispatcher.Invoke(new Action(
							delegate
							{
								Drawable bmp = getDrawable(pp);
								imageCache.put("chatpic" + Util.b64(mp.getDigest()), bmp);
							}));
					}
				}
				if (mp.getCmd() == C.USER_CACHE)
				{
					imageCache.clear();
				}
			}
		}
	}
}